#include "Serialization.h"
#include <GameObject/Components.h>

#include <iostream>
namespace Engine2D
{
    YAML::Node Serialization::SerializeObject(std::shared_ptr<IObject> obj)
    {
        YAML::Node root;
        obj->ForeachComponents([&](auto & comp) {
            Reflect<std::decay_t<decltype(comp)>> info;
            root[info.Name()] = Serialize(comp);
        }, AllComponents());
        root["Children"] = YAML::Node();
        obj->Foreach([&](std::shared_ptr<IObject> child) {
            root["Children"].push_back(SerializeObject(child));
            return IObject::ForeachEnum::Continue;
        }, false);
        return root;
    }
    
    std::shared_ptr<IObject> Serialization::DeSerializeObject(YAML::Node &node)
    {
        auto obj = std::make_shared<IObject>();
        for (auto iter = node.begin(); iter != node.end(); ++iter) {
            ForeachComponents([&](auto comp) {
                Reflect<decltype(comp)> info;
                if (iter->first.as<std::string>() == info.Name()) {
                    obj->AddComponent<decltype(comp)>(DeSerialize<decltype(comp)>(iter->second));
                }
            }, AllComponents());
        }
        for (auto iter = node["Children"].begin(); iter != node["Children"].end(); ++iter) {
            obj->AddChild(DeSerializeObject(*iter));
        }
        return obj;
    }
    
    YAML::Node Serialization::SerializeScene(std::shared_ptr<Scene> scene)
    {
        YAML::Node root = Serialize(*scene);
        root["Objects"] = YAML::Node();
        scene->Foreach([&](std::shared_ptr<IObject> obj) {
            root["Objects"].push_back(SerializeObject(obj));
            return IObject::ForeachEnum::Continue;
        });
        return root;
    }
    
    std::shared_ptr<Scene> Serialization::DeSerializeScene(YAML::Node &node)
    {
        auto scene = std::make_shared<Scene>();
        for (auto iter = node["Objects"].begin(); iter != node["Objects"].end(); ++iter) {
            scene->AddObject(DeSerializeObject(*iter));
        }
        return scene;
    }
} // namespace Engine2D
